home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / lib / posix / execlp.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  4KB  |  153 lines

  1. /* execlp(3) and execvp(3)
  2.  *
  3.  * Author: Terrence W. Holm      July 1988
  4.  */
  5.  
  6. /* FIXES - Dec 1989 - Jan 1990 Bruce Evans.
  7.  *     - Don't use search path when file name contains a '/' *anywhere*.
  8.  *     - Invoke sh(1) on command files.
  9.  *     - Use PATH_MAX and check strings fit in buffer.
  10.  *     - Use stdargs, with the unjustified assumption that va_start() turns
  11.  *       the arg list into a char *[].  Strictly, the arg list should be
  12.  *       copied, "wasting" up to ARG_MAX bytes.
  13.  */
  14.  
  15. /*  Execlp(3) and execvp(3) are like execl(3) and execv(3),
  16.  *  except that they use the environment variable $PATH as
  17.  *  a search list of possible locations for the executable
  18.  *  file, if <file> does not contain a '/', and they attempt
  19.  *  to run non-binary executable files using sh(1).
  20.  *
  21.  *  The path search list is a list of directory names separated
  22.  *  by ':'s. If a colon appears at the beginning or end of the
  23.  *  list, or two appear together, then an empty prefix is tried.
  24.  *  If $PATH is not in the environment, it defaults to "".
  25.  *
  26.  *  For example, if <file> is "ls", and the $PATH is
  27.  *  ":/usr/local/bin:/bin:/usr/bin", then  ./ls,
  28.  *  /usr/local/bin/ls, /bin/ls and /usr/bin/ls are tried until
  29.  *  an exectable one is found. If the direct attempt to exec it
  30.  *  fails, the arg list is modified to begin with "sh" and the
  31.  *  absolute name of <file>, and an exec of /bin/sh is tried.
  32.  *  If this fails, no further attempts are made.
  33.  *
  34.  *  This function only returns after an error.  It returns -1
  35.  *  and sets errno like execv().
  36.  */
  37.  
  38. #include <errno.h>
  39. #include <limits.h>
  40. #include <stdlib.h>
  41. #include <string.h>
  42. #include <sys/types.h>
  43. #include <unistd.h>
  44. #include <stdarg.h>
  45.  
  46. #undef NULL
  47. #define NULL 0            /* kludge for ACK not understanding void * */
  48.  
  49. extern char **environ;        /* environment pointer */
  50.  
  51. int execlp(file /* , ... */ )
  52. char *file;
  53. {
  54.   register va_list argp;
  55.   register int result;
  56.  
  57.   va_start(argp, file);
  58.   result = execvp(file, (char **) argp);
  59.   va_end(argp);
  60.   return(result);
  61. }
  62.  
  63. int execvp(file, argv)
  64. char *file;
  65. char **argv;
  66. {
  67.   register char **argp;
  68.   char **argtop;
  69.   int best_errno;
  70.   char **envtop;
  71.   size_t flength;
  72.   char *searchpath;
  73.   size_t slength;
  74.   char *split;
  75.   char execpath[PATH_MAX + 1];
  76.  
  77.   if (strchr(file, '/') != NULL || (searchpath = getenv("PATH")) == NULL)
  78.     searchpath = "";
  79.   flength = strlen(file);
  80.   best_errno = ENOENT;
  81.  
  82.   while (1) {
  83.     split = strchr(searchpath, ':');
  84.     if (split == NULL)
  85.         slength = strlen(searchpath);
  86.     else
  87.         slength = split - searchpath;
  88.     if (slength + flength >= sizeof execpath - 2) {
  89.         errno = ENAMETOOLONG;    /* too bad if premature */
  90.         return(-1);
  91.     }
  92.     strncpy(execpath, searchpath, slength);
  93.     if (slength != 0) execpath[slength++] = '/';
  94.     strcpy(execpath + slength, file);
  95.  
  96.     /* Don't try to avoid execv() for non-existent files, since the Minix
  97.      * shell doesn't, and it is not clear whether access() or stat() work
  98.      * right when this code is set-uid.
  99.      */
  100.     execv(execpath, argv);
  101.     switch (errno) {
  102.         case EACCES:
  103.         best_errno = errno;    /* more useful than ENOENT */
  104.         case ENOENT:
  105.         if (split == NULL) {
  106.             /* No more path components. */
  107.             errno = best_errno;
  108.             return(-1);
  109.         }
  110.         searchpath = split + 1;    /* try next in path */
  111.         break;
  112.         case ENOEXEC:
  113.         /* Assume a command file and invoke sh(1) on it.  Replace arg0
  114.          * (which is usually a short name for the command) by the full
  115.          * name of the command file.
  116.          */
  117.         *argv = execpath;
  118.  
  119.         /* Move the args up by 1, overlaying the assumed NULL at the
  120.          * end, to make room for "sh" at the beginning.
  121.          */
  122.         for (argp = argv; *argp != NULL; ) argp++;
  123.         argtop = argp + 1;
  124.         while (argp > argv) {
  125.             *argp = *(argp - 1);
  126.             --argp;
  127.         }
  128.         *argp = "sh";
  129.  
  130.         /* Count the environment pointers. */
  131.         for (envtop = environ; *envtop != NULL; ) envtop++;
  132.  
  133.         /* Try only /bin/sh, like the Minix shell.  Lose if the user
  134.          * has a different shell or the command has #!another/shell.
  135.          */
  136.         __execve("/bin/sh", argv, environ, argtop - argv,
  137.              envtop - environ);
  138.  
  139.         /* Oops, no shell?  Restore argv and give up. */
  140.         --argtop;
  141.         while (argv < argtop) {
  142.             *argp = *(argp + 1);
  143.             ++argp;
  144.         }
  145.         *argp = NULL;
  146.         errno = ENOEXEC;
  147.         return(-1);
  148.         default:
  149.         return(-1);    /* probably  ENOMEM or E2BIG */
  150.     }
  151.   }
  152. }
  153.